#include <gtest/gtest.h>
#include <memory>
#include "Executor.hpp"
#include "PoseEq.hpp"
namespace adas
{
    //Init
    TEST(ExecutorTest, should_return_init_pose_when_without_command)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        const Pose target({0, 0, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_default_pose_when_without_init_and_command)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor());
        //when
        const Pose target({0, 0, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //Move
    //CarMove
    TEST(ExecutorTest, should_return_x_plus_2_given_command_is_M_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("M");
        const Pose target({2, 0, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_2_given_command_is_M_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("M");
        const Pose target({-2, 0, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_plus_2_given_command_is_M_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("M");
        const Pose target({0, 2, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_minus_2_given_command_is_M_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("M");
        const Pose target({0, -2, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //BusMove
    TEST(ExecutorTest, should_return_x_plus_1_given_command_is_CM_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("CM");
        const Pose target({1, 0, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_1_given_command_is_CM_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("CM");
        const Pose target({-1, 0, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_plus_1_given_command_is_CM_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("CM");
        const Pose target({0, 1, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_minus_1_given_command_is_CM_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("CM");
        const Pose target({0, -1, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //Left
    //CarLeft
    TEST(ExecutorTest, should_return_y_plus_1_and_facing_N_given_command_is_L_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("L");
        const Pose target({0, 1, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_1_and_facing_W_given_command_is_L_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("L");
        const Pose target({-1, 0, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_minus_1_and_facing_S_given_command_is_L_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("L");
        const Pose target({0, -1, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_plus_1_and_facing_E_given_command_is_L_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("L");
        const Pose target({1, 0, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //BusLeft
    TEST(ExecutorTest, should_return_x_plus_1_and_facing_N_given_command_is_CL_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("CL");
        const Pose target({1, 0, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_plus_1_and_facing_W_given_command_is_CL_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("CL");
        const Pose target({0, 1, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_1_and_facing_S_given_command_is_CL_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("CL");
        const Pose target({-1, 0, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_minus_1_and_facing_E_given_command_is_CL_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("CL");
        const Pose target({0, -1, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //Right
    //CarRight
    TEST(ExecutorTest, should_return_y_minus_1_and_facing_S_given_command_is_R_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("R");
        const Pose target({0, -1, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_1_and_facing_W_given_command_is_R_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("R");
        const Pose target({-1, 0, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_plus_1_and_facing_N_given_command_is_R_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("R");
        const Pose target({0, 1, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_X_plus_1_and_facing_E_given_command_is_R_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("R");
        const Pose target({1, 0, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    //BusRight
    TEST(ExecutorTest, should_return_x_plus_1_and_facing_S_given_command_is_CR_and_facing_is_E)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'E'}));
        //when
        executor->Execute("CR");
        const Pose target({1, 0, 'S'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_minus_1_and_facing_W_given_command_is_CR_and_facing_is_S)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'S'}));
        //when
        executor->Execute("CR");
        const Pose target({0, -1, 'W'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_x_minus_1_and_facing_N_given_command_is_CR_and_facing_is_W)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'W'}));
        //when
        executor->Execute("CR");
        const Pose target({-1, 0, 'N'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
    TEST(ExecutorTest, should_return_y_plus_1_and_facing_E_given_command_is_CR_and_facing_is_N)
    {
        //given
        std::unique_ptr<Executor> executor(Executor::NewExecutor({0, 0, 'N'}));
        //when
        executor->Execute("CR");
        const Pose target({0, 1, 'E'});
        //then
        ASSERT_EQ(target, executor->Query());
    }
}